<template>
  <div class="snake-game">
    <h1>贪吃蛇游戏</h1>
    <div class="game-board" ref="gameBoard">
      <div 
        v-for="(row, rowIndex) in board" 
        :key="rowIndex" 
        class="row"
      >
        <div 
          v-for="(cell, colIndex) in row" 
          :key="colIndex" 
          :class="[
            'cell', 
            { 'snake': cell === 1, 'food': cell === 2 }
          ]"
        ></div>
      </div>
    </div>
    <div class="game-controls">
      <p>得分: {{ score }}</p>
      <button @click="startGame">开始游戏</button>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, onMounted, onUnmounted } from 'vue'

export default defineComponent({
  name: 'SnakeGame',
  setup() {
    const boardSize = 20
    const board = ref<number[][]>([])
    const snake = ref<[number, number][]>([])
    const food = ref<[number, number]>([0, 0])
    const direction = ref<[number, number]>([0, 1])
    const score = ref(0)
    const gameSpeed = ref(200)
    let gameInterval: number

    const initializeBoard = () => {
      board.value = Array.from({ length: boardSize }, () => 
        Array(boardSize).fill(0)
      )
      snake.value = [[10, 10]]
      placeFood()
      updateBoard()
    }

    const placeFood = () => {
      let x, y
      do {
        x = Math.floor(Math.random() * boardSize)
        y = Math.floor(Math.random() * boardSize)
      } while (snake.value.some(([sx, sy]) => sx === x && sy === y))
      
      food.value = [x, y]
    }

    const updateBoard = () => {
      board.value.forEach(row => row.fill(0))
      snake.value.forEach(([x, y]) => {
        board.value[x][y] = 1
      })
      board.value[food.value[0]][food.value[1]] = 2
    }

    const moveSnake = () => {
      const [dx, dy] = direction.value
      const [headX, headY] = snake.value[0]
      const newHead: [number, number] = [
        (headX + dx + boardSize) % boardSize, 
        (headY + dy + boardSize) % boardSize
      ]

      if (isCollision(newHead)) {
        clearInterval(gameInterval)
        alert('游戏结束!')
        return
      }

      snake.value.unshift(newHead)

      if (newHead[0] === food.value[0] && newHead[1] === food.value[1]) {
        score.value++
        placeFood()
      } else {
        snake.value.pop()
      }

      updateBoard()
    }

    const isCollision = (head: [number, number]) => {
      return snake.value.slice(1).some(
        ([x, y]) => x === head[0] && y === head[1]
      )
    }

    const handleKeydown = (e: KeyboardEvent) => {
      switch(e.key) {
        case 'ArrowUp': 
          if (direction.value[0] !== 1) direction.value = [-1, 0]
          break
        case 'ArrowDown': 
          if (direction.value[0] !== -1) direction.value = [1, 0]
          break
        case 'ArrowLeft': 
          if (direction.value[1] !== 1) direction.value = [0, -1]
          break
        case 'ArrowRight': 
          if (direction.value[1] !== -1) direction.value = [0, 1]
          break
      }
    }

    const startGame = () => {
      initializeBoard()
      score.value = 0
      clearInterval(gameInterval)
      gameInterval = setInterval(moveSnake, gameSpeed.value)
    }

    onMounted(() => {
      window.addEventListener('keydown', handleKeydown)
      initializeBoard()
    })

    onUnmounted(() => {
      window.removeEventListener('keydown', handleKeydown)
      clearInterval(gameInterval)
    })

    return {
      board,
      score,
      startGame
    }
  }
})
</script>

<style scoped>
.snake-game {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: Arial, sans-serif;
}

.game-board {
  display: flex;
  flex-direction: column;
  border: 2px solid #333;
}

.row {
  display: flex;
}

.cell {
  width: 20px;
  height: 20px;
  border: 1px solid #eee;
  background-color: #f0f0f0;
}

.cell.snake {
  background-color: green;
}

.cell.food {
  background-color: red;
}

.game-controls {
  margin-top: 20px;
  text-align: center;
}

button {
  padding: 10px 20px;
  font-size: 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  cursor: pointer;
}
</style>
